Imports System
Imports System.Text
Imports System.Data
Imports System.Collections.Generic
Imports System.Web
Imports System.IO

Imports Framework

'Collection Class (Customisable half)
Partial Public Class CItemList
        
#Region "Filters"
    Public ReadOnly Property Unassigned As CItemList
        Get
            Return GetByAssignedToUserId(Integer.MinValue)
        End Get
    End Property

#End Region

#Region "Aggregation"
#End Region

#Region "Searching (Optional)"
    'Represents a simple search box to search PK and any string columns (add overloads as required, based on the pattern below)
    'e.g. Public Function Search(ByVal nameOrId As String, ByVal statusId As Integer, ByVal createdByUserId As Integer, ByVal assignedToUserId As Integer, ByVal reviewedByUserId As Integer, ByVal priorityId As Integer, ByVal categoryId As Integer) As CItemList
    Public Function Search(ByVal searchFor As String, assignedToUserId As Integer, categoryId As Integer, statusId As Integer, priorityId As Integer, completeStatusIdFromConfig As Integer) As CItemList
        '1. Normalisation
        If IsNothing(searchFor) Then searchFor = String.Empty
        searchFor = searchFor.Trim.ToLower()

        '2. Start with a complete list
        Dim results As CItemList = Me

        '3. Use any available index, such as those generated for fk/bool columns
        'Normal Case - non-unique index (e.g. foreign key)
        If Integer.MinValue <> assignedToUserId Then results = results.GetByAssignedToUserId123(assignedToUserId) 'Any of the 3 users can match
        If Integer.MinValue <> priorityId Then results = results.GetByPriorityId(priorityId)
        If Integer.MinValue <> categoryId Then results = results.GetByCategoryId(categoryId)
        If statusId > 0 Then results = results.GetByStatusId(statusId)
        If statusId = 0 Then
            Dim temp As New CItemList(results.Count)
            For Each i As CItem In results
                If i.ItemStatusId <> completeStatusIdFromConfig Then temp.Add(i)
            Next
            results = temp
        End If

        '4. Exit early if remaining (non-index) filters are blank
        If String.IsNullOrEmpty(searchFor) Then Return results


        '5. Manually search each record using custom match logic, building a shortlist
        Dim shortList As New CItemList(results)
        For Each i As CItem In results
            If Match(searchFor, i) Then shortList.Add(i)
        Next
        Return shortList
    End Function
    'Manual Searching e.g for string-based columns i.e. anything not indexed (add more params if required)
    Private Function Match(ByVal name As String, ByVal obj As CItem) As Boolean
        If Not String.IsNullOrEmpty(name) Then
            If Not IsNothing(obj.ItemName) AndAlso obj.ItemName.ToLower().Contains(name) Then Return True
            If Not IsNothing(obj.ItemDescription) AndAlso obj.ItemDescription.ToLower().Contains(name) Then Return True
            If obj.ItemId.ToString = name Then Return True
            Return False 'If filter is active, reject any items that dont match
        End If
        Return True 'No active filters (should catch this in step #4)
    End Function
#End Region

#Region "Cloning"
    Public Function Clone(ByVal target As CDataSrc) As CItemList ', parentId As Integer) As CItemList
        'No Transaction
        If TypeOf target Is CDataSrcRemote Then Return Clone(target, Nothing) ', parentId)

        'Transaction
        Dim cn As IDbConnection = target.Local.Connection()
        Dim tx As IDbTransaction = cn.BeginTransaction()
        Try
            Clone = Clone(target, tx) ', parentId)
            tx.Commit()
        Catch
            tx.Rollback()
            Throw
        Finally
            cn.Close()
        End Try
    End Function
    Public Function Clone(target As CDataSrc, txOrNull As IDbTransaction) As CItemList ', parentId As Integer) As CItemList
        Dim list As New CItemList(Me.Count)
        For Each i As CItem In Me
            list.Add(i.Clone(target, txOrNull))  ', parentId))    *Child entities must reference the new parent
        Next
        Return list
    End Function
#End Region

#Region "Export to Csv"
    'Web - Need to add a project reference to System.Web, or comment out these two methods
    Public Sub ExportToCsv(ByVal response As HttpResponse)
        ExportToCsv(response, "Items.csv")
    End Sub
    Public Sub ExportToCsv(ByVal response As HttpResponse, ByVal fileName As String)
        CDataSrc.ExportToCsv(response, fileName) 'Standard response headers
        Dim sw As New StreamWriter(response.OutputStream)
        ExportToCsv(sw)
        sw.Flush()
        response.End()
    End Sub

    'Non-web
    Public Sub ExportToCsv(ByVal filePath As String)
        Dim sw As New StreamWriter(filePath)
        ExportToCsv(sw)
        sw.Close()
    End Sub

    'Logic
    Protected Sub ExportToCsv(ByVal sw As StreamWriter)
        Dim headings As String() = New String() {"ItemId", "ItemName", "ItemDescription", "ItemStatusId", "ItemCreatedByUserId", "ItemAssignedToUserId", "ItemAssignedToUserId2", "ItemAssignedToUserId3", "ItemPriorityId", "ItemCategoryId", "ItemDateCreated", "ItemDateStarted", "ItemDateReviewed", "ItemDateCompleted"}
        CDataSrc.ExportToCsv(headings, sw)
        For Each i As CItem In Me
            Dim data As Object() = New Object() {i.ItemId, i.ItemName, i.ItemDescription, i.ItemStatusId, i.ItemCreatedByUserId, i.ItemAssignedToUserId, i.ItemAssignedToUserId2, i.ItemAssignedToUserId3, i.ItemPriorityId, i.ItemCategoryId, i.ItemDateCreated, i.ItemDateStarted, i.ItemDateReviewed, i.ItemDateCompleted}
            CDataSrc.ExportToCsv(data, sw)
        Next
    End Sub
#End Region


    'Index by ItemAssignedToUserId
    Public Function GetByAssignedToUserId123(ByVal assignedToUserId123 As Integer) As CItemList
        Dim temp As CItemList = Nothing
        If Not IndexByAssignedToUserId123.TryGetValue(assignedToUserId123, temp) Then
            temp = New CItemList(Unassigned)
            IndexByAssignedToUserId123(assignedToUserId123) = temp
        End If
        Return temp
    End Function
    <NonSerialized()> _
    Private _indexByAssignedToUserId123 As Dictionary(Of Integer, CItemList)
    Private ReadOnly Property IndexByAssignedToUserId123() As Dictionary(Of Integer, CItemList)
        Get
            If IsNothing(_indexByAssignedToUserId123) Then
                'Instantiate
                Dim index As New Dictionary(Of Integer, CItemList)()

                'Populate
                Dim temp As CItemList = Nothing
                For Each i As CItem In Me
                    If i.ItemAssignedToUserId <= 0 Then Continue For
                    If Not index.TryGetValue(i.ItemAssignedToUserId, temp) Then
                        temp = New CItemList()
                        index(i.ItemAssignedToUserId) = temp
                    End If
                    temp.Add(i)
                Next
                For Each i As CItem In Me
                    If i.ItemAssignedToUserId2 <= 0 Then Continue For
                    If Not index.TryGetValue(i.ItemAssignedToUserId2, temp) Then
                        temp = New CItemList()
                        index(i.ItemAssignedToUserId2) = temp
                    End If
                    If Not temp.Contains(i) Then temp.Add(i)
                Next
                For Each i As CItem In Me
                    If i.ItemAssignedToUserId3 <= 0 Then Continue For
                    If Not index.TryGetValue(i.ItemAssignedToUserId3, temp) Then
                        temp = New CItemList()
                        index(i.ItemAssignedToUserId3) = temp
                    End If
                    If Not temp.Contains(i) Then temp.Add(i)
                Next
                For Each i As CItem In Me
                    If i.ItemAssignedToUserId4 <= 0 Then Continue For
                    If Not index.TryGetValue(i.ItemAssignedToUserId4, temp) Then
                        temp = New CItemList()
                        index(i.ItemAssignedToUserId4) = temp
                    End If
                    If Not temp.Contains(i) Then temp.Add(i)
                Next

                'Add the unassigned ones
                For Each temp In index.Values
                    temp.AddRange(Unassigned)
                    temp.Sort()
                Next

                'Store
                _indexByAssignedToUserId123 = index
            End If
            Return _indexByAssignedToUserId123
        End Get
    End Property

End Class
